﻿using QuDao;
using Kalman;
using Kalman.Extensions;
using Newtonsoft.Json.Linq;
using NLog;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.Encodings.Web;
using System.Web;

namespace Wechat.TenpayV3
{
    /// <summary>
    /// 微信支付APIv3客户端
    /// </summary>
    public sealed partial class TenpayClient : SingletonBase<TenpayClient>
    {
        readonly AppSettings appSettings;
        readonly ILogger log;
        readonly string baseUrl = "https://api.mch.weixin.qq.com";

        public TenpayClient() : base()
        {
            appSettings = AppSettings.Load();
            log = LogManager.GetLogger("WxPay");
        }

        /// <summary>
        /// 支付结果通知回调url，用于商户接收支付结果（微信小程序支付）
        /// </summary>
        public string NotifyUrl
        {
            get
            {
                return "https://api-ac.banan8.com/WxApp/PayNotify";
            }
        }

        /// <summary>
        /// 生成小程序调起支付用到的参数数据
        /// </summary>
        /// <param name="app">微信应用对象</param>
        /// <param name="openid">小程序用户openid</param>
        /// <param name="out_trade_no">订单号</param>
        /// <param name="total_fee">总金额，单位：分</param>
        /// <param name="desc">商品描述</param>
        /// <returns></returns>
        public IDictionary<string, string> GeneratePayParameters(WxApp app, string openid, string out_trade_no, int total_fee, string desc)
        {
            //var isPartner = !string.IsNullOrEmpty(app.SP_MchID); //是否服务商模式
            //var mch = MerchantBO.Instance.GetItem(app.MchID);
            //if (mch == null) throw new AppException($"微信商户不存在：{app.MchID}");

            //var apiKey = mch.ApiKey;
            //var privateKey = mch.PrivateKey;
            //var mchid = mch.MchID;
            //var certSN = mch.CertSN;
            //var nonce = GetNoncestr();
            //var timestamp = GetTimestamp();
            //var uri = "/v3/pay/transactions/jsapi";

            //var body = new JObject
            //{
            //    ["out_trade_no"] = out_trade_no,
            //    ["description"] = desc,
            //    //["notify_url"] = NotifyUrl,
            //    ["amount"] = new JObject { { "total", total_fee } },
            //};

            //if (isPartner) //服务商模式
            //{
            //    var sp_mch = MerchantBO.Instance.GetItem(app.SP_MchID);
            //    if (sp_mch == null) throw new AppException($"服务商商户不存在：{app.SP_MchID}");

            //    uri = "/v3/pay/partner/transactions/jsapi";
            //    //apiKey = sp_mch.ApiKey;
            //    privateKey = sp_mch.PrivateKey;
            //    mchid = sp_mch.MchID;
            //    certSN = sp_mch.CertSN;

            //    body["sp_appid"] = sp_mch.AppID;
            //    body["sp_mchid"] = sp_mch.MchID;
            //    body["sub_appid"] = app.WxAppID;
            //    body["sub_mchid"] = app.MchID;
            //    body["payer"] = new JObject { { "sub_openid", openid } };
            //}
            //else //普通商户模式
            //{
            //    body["appid"] = app.WxAppID;
            //    body["mchid"] = app.MchID;
            //    body["payer"] = new JObject { { "openid", openid } };
            //}

            ////var keyString = Encrypt(apiKey);//对Api密钥进行加密并附加到通知Url地址，处理通知的时候解密出密钥用于解密通知数据，还可以省去验签步骤
            //body["notify_url"] = $"{NotifyUrl}/{mchid}";

            //var message = $"POST\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            //var sign = RSAUtility.SignWithSHA256(privateKey, message);
            //var auth = $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{certSN}\",signature=\"{sign}\"";

            ////小程序下单，获取预支付交易会话标识
            ////服务商：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_1.shtml
            ////直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml
            //var result = Execute(uri, auth, body);
            //var prepay_id = result["prepay_id"].ToString();

            ////生成小程序调起支付用到的参数数据
            ////服务商：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_4.shtml
            ////直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
            //var package = $"prepay_id={prepay_id}";//预支付交易会话标识。用于后续接口调用中使用，该值有效期为2小时，示例：wx2611215250487459928b659bd466620000
            //sign = RSAUtility.SignWithSHA256(
            //    //privateKey: cfg.PRIVATE_KEY,
            //    privateKey: privateKey,
            //    plainText: $"{app.WxAppID}\n{timestamp}\n{nonce}\n{package}\n"
            //);

            //var dic = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>()
            //{
            //    { "appId", app.WxAppID },
            //    //{ "partnerid", app.MchID },
            //    { "timeStamp", timestamp.ToString() },
            //    { "nonceStr", nonce },
            //    { "package", package },
            //    { "signType", "RSA" },
            //    { "paySign", sign }
            //});
            //return dic;
            return null;
        }

        //public IDictionary<string, string> GenerateTest()
        //{
        //    var mchid = "1587004061";
        //    var appid = "wx72d1996050a3a513";
        //    var body = new JObject
        //    {
        //        ["appid"] = appid,
        //        ["mchid"] = mchid,
        //        ["out_trade_no"] = "G26595344721926",
        //        ["description"] = "特价豪华大床房",
        //        ["notify_url"] = NotifyUrl,
        //        ["amount"] = new JObject { { "total", 10 } },
        //        ["payer"] = new JObject { { "openid", "oPQQJ0XmIN1dWT8Y2TUAIZdmjbBE" } }
        //    };

        //    var cert_sn = "2E6709C06F977A2ADDB5DC003B0EF4918E1F3516";
        //    var privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC09vJ5AitfLkrObUUJZ9ZDxuM26Es2BYTb+s9p+l6/j37b7/09BT3Q1X7N448m8I0LoglOLW3BsFzQd7EzXieP43iXJIJxV+Cc3qLmVk2kvFtVhTli+AGJ8xBjegpkOzUdkGoHUXTVNqOXXYfF31ZtVBt+qss7jLn82m06NqNDqf0Bh4zFny4lFZLBo+f299Zpe0/BmVbVI83tl3nOyZE3TFc7PMn8RXYIL4GGvfX71gjczMQlTv9Cgfa0GYrNV/p97YUcr5RJsv3eqwaAGpU3VlZLUL7qbVYaS0j2bleyZf3Ovsvi5PfI4Inqw5q+5zA5Eo+cyXL/fnjOqFOiAc3RAgMBAAECggEATrk3FklJUOi0hkSmycawQV/eLF61iVSxTXk4jePrH+5uw4MNaWREVfrqZOrftZLj6PGelrHQk3gDiHTpU21cTI4qQaYSUPhnsBZySz20HTwLh5KjOlilYruon33R03SmUKwoU/KtnqtcU1bO39eeo4T5SQtHyioYJtVmuvJV5/Lp1oYevGnrvavDaGc0nhsBH9Mu38w5uAJet4TcugQUaKa6sP1wWZirzTCPmfWpMsyOi1L8cQsNqioWwCoX0CfLWooJATQQellR14DRmuCjFOPDMqdd+B+QZwilUL/mWKheqwkI/S0geDh+Hzg7ih6CZ09MwkgNrns+zf3nzwByOQKBgQDc830L3na4W7et0JN4tEDRTYVT2yUUDqauASyaaGEvO1GszKhWMBepeeiATdfGHEXL+a95R9V3mRpchtZKisJiTrfO0RhsrmIyobI9kCxYOVTFtxQCfpjdpLTkFRgzuGoXIJQ2ZVqhMo279LdC2yF0jnc4LhdCtwfhgGeguXVEfwKBgQDRq6oEwBL/iGWf8XQq5frkeJIXh5rXHIJ84NaDrXHcb//hMLYYQNQw5Eu9HlhSUFPnHi88NezoW6DPZ2McG3AnuX8hiHFNAsJO/jyIZY6uTB5Va24ictsg40TuQEXTA5p2trehcu0BioQZDHUWzfhfJTHn6cbuXsJvyR6B6L6FrwKBgDtYv1any1WbdQufwWyjZeGSI+SxMRVhFg4YzKUwsiHgmgCC/BgiVMi1sOh9gB57S5gNGb/GtqSoH/eIVBiziqCjKiXH7fqLIF8fJWP5zJ9pzsZIdXxyCpdF/TxiGh0SRJSvsH+n257+mClLAspXV3YaKhWR87d8uAYu2ibGiaP7AoGABzybk6plfXhhuZGF5u0lKbmXoURG7eHIBzNjdAwKgAdFl6osvs2OBVn72z0u4zhujO2Xx8Y8tRBkjoQNAa1Yw6Y9YxTohDXyKvPPdw26TP3Hlj8s//di5NGzUV3aixv2ut43nFTxJTp4sLyjVfQp/G62OEDzYsrWfzE74lP8L3UCgYEAnH3dd0QPk2fqUqiWaULRmNxoxkjQtT80ZPxdxNZU/piucbcrHGyWaMAwPfx+hKeVpZH7u2aPrPV0DjM5xSIu/rC41uTfjf7Bt0rS7jCJXLHNnsQfuit+ukYqXpcvNHBY1U18uokBhtjC+GSA4UE0QTWSJJm0WZgimUrdGIpCRYc=";
        //    var uri = "/v3/pay/transactions/jsapi";
        //    var nonce = GetNoncestr();
        //    var timestamp = GetTimestamp();
        //    var message = $"POST\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
        //    var sign = RSAUtility.SignWithSHA256(privateKey, message);
        //    var auth = $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{cert_sn}\",signature=\"{sign}\"";

        //    //小程序下单，获取预支付交易会话标识，参考：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_1.shtml
        //    var result = Execute(uri, auth, body);
        //    var prepay_id = result["prepay_id"].ToString();

        //    //生成小程序调起支付用到的参数数据，参考：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_4.shtml
        //    var package = $"prepay_id={prepay_id}";//预支付交易会话标识。用于后续接口调用中使用，该值有效期为2小时，示例：wx2611215250487459928b659bd466620000
        //    sign = RSAUtility.SignWithSHA256(
        //        privateKey: privateKey,
        //        plainText: $"{appid}\n{timestamp}\n{nonce}\n{package}\n"
        //    );

        //    var dic = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>()
        //    {
        //        { "appId", appid },
        //        { "timeStamp", timestamp.ToString() },
        //        { "nonceStr", nonce },
        //        { "package", package },
        //        { "signType", "RSA" },
        //        { "paySign", sign }
        //    });
        //    return dic;
        //}

        /// <summary>
        /// 解析支付通知数据
        /// </summary>
        /// <param name="mchid">微信商户号</param>
        /// <param name="json">微信支付通知数据</param>
        /// <param name="sign">签名字符串</param>
        /// <returns></returns>
        public TransactionData ParsePayNotify(string mchid, string json, string sign)
        {
            //服务商：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_5.shtml
            //直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_5.shtml
            var jo = JObject.Parse(json);
            if (!jo.ContainsKey("resource")) throw new AppException("无效的通知数据");

            //var mch = MerchantBO.Instance.GetItem(mchid);
            //if (mch == null) throw new AppException($"微信商户不存在：{mchid}");

            //var apiKey = Decrypt(keyString);
            var nonce = jo["resource"]["nonce"].ToString();
            var ciphertext = jo["resource"]["ciphertext"].ToString();
            var associated_data = jo["resource"]["associated_data"].ToString();

            ///TODO：检验签名

            var plaintext = AESUtility.DecryptWithGCM("mch.ApiKey", nonce, associated_data, ciphertext);
            //var plaintext = AesGcm.Decrypt(cfg.APIv3_KEY, associated_data, nonce, ciphertext);
            log.Info($"微信支付通知：{plaintext}");

            return new TransactionData(plaintext);
        }

        /// <summary>
        /// 查询交易订单（transaction_id和out_trade_no二选一）
        /// </summary>
        /// <param name="app">微信应用对象</param>
        /// <param name="transaction_id">微信支付交易ID</param>
        /// <param name="out_trade_no">商户订单号（加前缀）</param>
        /// <param name="isNotify">是否处理补单通知，默认false，不处理</param>
        /// <returns></returns>
        public TransactionData QueryOrder(WxApp app, string transaction_id, string out_trade_no, bool isNotify = false)
        {
            //var isPartner = !string.IsNullOrEmpty(app.SP_MchID); //是否服务商模式
            //var mch = MerchantBO.Instance.GetItem(app.MchID);
            //if (mch == null) throw new AppException($"微信商户不存在：{app.MchID}");

            ////订单查询，服务商：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_2.shtml  直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_2.shtml
            //var uri = string.Empty;
            //var mchid = mch.MchID;
            //var certSN = mch.CertSN;
            //var privateKey = mch.PrivateKey;
            //if (isPartner)
            //{
            //    var sp_mch = MerchantBO.Instance.GetItem(app.SP_MchID);
            //    if (sp_mch == null) throw new AppException($"服务商商户不存在：{app.SP_MchID}");

            //    mchid = sp_mch.MchID;
            //    certSN = sp_mch.CertSN;
            //    privateKey = sp_mch.PrivateKey;
            //    if (!string.IsNullOrEmpty(out_trade_no)) uri = $"/v3/pay/partner/transactions/out-trade-no/{out_trade_no}?sp_mchid={app.SP_MchID}&sub_mchid={app.MchID}";
            //    if (!string.IsNullOrEmpty(transaction_id)) uri = $"/v3/pay/partner/transactions/id/{transaction_id}?sp_mchid={app.SP_MchID}&sub_mchid={app.MchID}";
            //}
            //else
            //{
            //    if (!string.IsNullOrEmpty(out_trade_no)) uri = $"/v3/pay/transactions/out-trade-no/{out_trade_no}?mchid={mchid}";
            //    if (!string.IsNullOrEmpty(transaction_id)) uri = $"/v3/pay/transactions/id/{transaction_id}?mchid={mchid}";
            //}

            //var nonce = GetNoncestr();
            //var timestamp = GetTimestamp();
            //var message = $"GET\n{uri}\n{timestamp}\n{nonce}\n\n";
            //var sign = RSAUtility.SignWithSHA256(privateKey, message);
            //var auth = $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{certSN}\",signature=\"{sign}\"";

            //var result = Execute(uri, auth, null);
            //var data = new TransactionData(result);

            //if (isNotify) PaymentBO.Instance.PayNotify(data);//处理补单通知
            //return data;
            return null;
        }

        /// <summary>
        /// 关闭交易订单
        /// </summary>
        /// <param name="app">微信应用对象</param>
        /// <param name="out_trade_no">商户订单号（加前缀）</param>
        public void CloseOrder(WxApp app, string out_trade_no)
        {
            //var body = new JObject();
            //var isPartner = !string.IsNullOrEmpty(app.SP_MchID); //是否服务商模式
            //var mch = MerchantBO.Instance.GetItem(app.MchID);
            //if (mch == null) throw new AppException($"微信商户不存在：{app.MchID}");
            //var mchid = mch.MchID;
            //var certSN = mch.CertSN;
            //var privateKey = mch.PrivateKey;

            ////订单关闭，服务商：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_3.shtml  直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_3.shtml
            //string uri;
            //if (isPartner)
            //{
            //    var sp_mch = MerchantBO.Instance.GetItem(app.SP_MchID);
            //    if (sp_mch == null) throw new AppException($"服务商商户不存在：{app.SP_MchID}");

            //    mchid = sp_mch.MchID;
            //    certSN = sp_mch.CertSN;
            //    privateKey = sp_mch.PrivateKey;
            //    uri = $"/v3/pay/partner/transactions/out-trade-no/{out_trade_no}/close";

            //    body["sp_mchid"] = sp_mch.MchID;
            //    body["sub_mchid"] = mch.MchID;
            //}
            //else
            //{
            //    uri = $"/v3/pay/transactions/out-trade-no/{out_trade_no}/close";
            //    body["mchid"] = mch.MchID;
            //}

            //var nonce = GetNoncestr();
            //var timestamp = GetTimestamp();
            //var message = $"POST\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            //var sign = RSAUtility.SignWithSHA256(privateKey, message);
            //var auth = $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{certSN}\",signature=\"{sign}\"";

            //Execute(uri, auth, body);
        }

        /// <summary>
        /// 申请退款
        /// </summary>
        /// <param name="app">微信应用对象</param>
        /// <param name="transaction_id">微信支付交易ID</param>
        /// <param name="out_refund_no">商户退款单号（多次退款不能用同一退款单号）</param>
        /// <param name="totalAmount">订单总金额，单位：元</param>
        /// <param name="refundAmount">退款金额，不能大于总金额</param>
        /// <param name="reason">退款原因</param>
        public RefundData ApplyRefund(WxApp app, string transaction_id, string out_refund_no, decimal totalAmount, decimal refundAmount, string reason)
        {
            var total = (int)decimal.Round(totalAmount * 100, 0);
            var refund = (int)decimal.Round(refundAmount * 100, 0);
            var body = new JObject
            {
                ["transaction_id"] = transaction_id,
                ["out_refund_no"] = out_refund_no,
                //["notify_url"] = "",//不做退款异步通知
                ["amount"] = new JObject { { "refund", refund }, { "total", total } }
            };
            if (!string.IsNullOrEmpty(reason)) body["reason"] = reason;

            //var isPartner = !string.IsNullOrEmpty(app.SP_MchID); //是否服务商模式
            //var mch = MerchantBO.Instance.GetItem(app.MchID);
            //if (mch == null) throw new AppException($"微信商户不存在：{app.MchID}");
            //var mchid = mch.MchID;
            //var certSN = mch.CertSN;
            //var privateKey = mch.PrivateKey;
            //var uri = $"/v3/refund/domestic/refunds";

            ////申请退款，服务商：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_9.shtml  直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_9.shtml
            //if (isPartner)
            //{
            //    var sp_mch = MerchantBO.Instance.GetItem(app.SP_MchID) ?? throw new AppException($"服务商商户不存在：{app.SP_MchID}");
            //    mchid = sp_mch.MchID;
            //    certSN = sp_mch.CertSN;
            //    privateKey = sp_mch.PrivateKey;

            //    body["sub_mchid"] = mch.MchID;
            //}

            //var nonce = GetNoncestr();
            //var timestamp = GetTimestamp();
            //var message = $"POST\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            //var sign = RSAUtility.SignWithSHA256(privateKey, message);
            //var auth = $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{certSN}\",signature=\"{sign}\"";

            //var result = Execute(uri, auth, body);
            //var data = new RefundData(result);
            //return data;
            return null;
        }

        /// <summary>
        /// 查询单笔退款
        /// </summary>
        /// <param name="app">微信应用对象</param>
        /// <param name="out_refund_no">商户系统内部的退款单号，商户系统内部唯一</param>
        /// <param name="isNotify">是否处理补单通知，默认false，不处理</param>
        /// <returns></returns>
        public RefundData QueryRefund(WxApp app, string out_refund_no, bool isNotify = false)
        {
            //var isPartner = !string.IsNullOrEmpty(app.SP_MchID); //是否服务商模式
            //var mch = MerchantBO.Instance.GetItem(app.MchID);
            //if (mch == null) throw new AppException($"微信商户不存在：{app.MchID}");
            //var mchid = mch.MchID;
            //var certSN = mch.CertSN;
            //var privateKey = mch.PrivateKey;
            //var uri = $"/v3/refund/domestic/refunds/{out_refund_no}";

            ////查询单笔退款，服务商：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_10.shtml  直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_10.shtml
            //if (isPartner)
            //{
            //    var sp_mch = MerchantBO.Instance.GetItem(app.SP_MchID);
            //    if (sp_mch == null) throw new AppException($"服务商商户不存在：{app.SP_MchID}");

            //    mchid = sp_mch.MchID;
            //    certSN = sp_mch.CertSN;
            //    privateKey = sp_mch.PrivateKey;

            //    uri = $"/v3/refund/domestic/refunds/{out_refund_no}?sub_mchid={app.MchID}";
            //}

            //var nonce = GetNoncestr();
            //var timestamp = GetTimestamp();
            //var message = $"GET\n{uri}\n{timestamp}\n{nonce}\n\n";
            //var sign = RSAUtility.SignWithSHA256(privateKey, message);
            //var auth = $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{certSN}\",signature=\"{sign}\"";

            //var result = Execute(uri, auth, null);
            //var data = new RefundData(result);

            //if (isNotify) PaymentBO.Instance.RefundNotify(data);//处理补单通知
            //return data;
            return null;
        }


        /// <summary>
        /// 商家转账到零钱（单笔打款，不支持服务商模式），文档：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml
        /// </summary>
        /// <param name="app">微信应用对象</param>
        /// <param name="openid">小程序用户openid</param>
        /// <param name="out_trade_no">商家交易订单号</param>
        /// <param name="amount">转账金额，不超过2000元</param>
        /// <param name="desc">转账描述</param>
        /// <returns></returns>
        public JObject TransferToBalance(WxApp app, string openid, string out_trade_no, decimal amount, string desc)
        {
            //if (amount > 200000) throw new AppException("单笔转账金额不能大于2000元");
            //var mch = MerchantBO.Instance.GetItem(app.MchID) ?? throw new AppException($"微信商户不存在：{app.MchID}");

            ////var apiKey = mch.ApiKey;
            //var privateKey = mch.PrivateKey;
            //var mchid = mch.MchID;
            //var certSN = mch.CertSN;
            //var nonce = GetNoncestr();
            //var timestamp = GetTimestamp();
            //var uri = "/v3/transfer/batches";
            //var total_fee = (int)decimal.Round(amount * 100, 0);
            //var batchNo = $"{DateTime.Now:yyyyMMddHHmmssff}";

            //var body = new JObject
            //{
            //    ["appid"] = app.WxAppID,            //直连商户的appid	appid	string[1,32]	是	body申请商户号的appid或商户号绑定的appid（企业号corpid即为此appid）
            //    ["out_batch_no"] = batchNo,         //商家批次单号out_batch_no	string[1,32]	是	body商户系统内部的商家批次单号，要求此参数只能由数字、大小写字母组成，在商户系统内部唯一
            //    ["batch_name"] = desc,              //批次名称	batch_name	    string[1,32]	是	body该笔批量转账的名称
            //    ["batch_remark"] = desc,            //批次备注	batch_remark	string[1,32]	是	body转账说明，UTF8编码，最多允许32个字符
            //    ["total_num"] = 1,                  //转账总笔数	total_num	int	是	body一个转账批次单最多发起三千笔转账。转账总笔数必须与批次内所有明细之和保持一致，否则无法发起转账操作
            //    ["total_amount"] = total_fee,       //转账总金额	total_amount	int	是	body转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致，否则无法发起转账操作
            //    //["transfer_scene_id"] = "1001",    //转账场景ID	transfer_scene_id	string[4, 10]	否	该批次转账使用的转账场景，可在「商家转账到零钱 - 产品设置」中查看详情，如不填写则使用商家的默认转账场景，如：1001 - 现金营销
            //};

            ///* user_name
            // *  1、明细转账金额 >= 2,000元，收款用户姓名必填；
            //    2、同一批次转账明细中，收款用户姓名字段需全部填写、或全部不填写；
            //    3、 若传入收款用户姓名，微信支付会校验用户openID与姓名是否一致，并提供电子回单；
            //    4、收款方姓名。采用标准RSA算法，公钥由微信侧提供
            //    5、该字段需进行加密处理，加密方法详见敏感信息加密说明。(提醒：必须在HTTP头中上送Wechatpay-Serial)
            //    6、商户需确保收集用户的姓名信息，以及向微信支付传输用户姓名和账号标识信息做一致性校验已合法征得用户授权
            //    示例值：757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45
            // */
            //var transItem = new JObject
            //{
            //    ["out_detail_no"] = out_trade_no,      //商家明细单号	out_detail_no	string[1,32]	是	商户系统内部区分转账批次单下不同转账明细单的唯一标识，要求此参数只能由数字、大小写字母组成
            //    ["transfer_amount"] = total_fee,    //转账金额	transfer_amount	int	是	转账金额单位为分
            //    ["transfer_remark"] = desc,      //转账备注	transfer_remark	string[1,32]	是	单条转账备注（微信用户会收到该备注），UTF8编码，最多允许32个字符
            //    ["openid"] = openid,  //用户在直连商户应用下的用户标示	openid	string[1,128]	是	openid是微信用户在公众号appid下的唯一用户标识（appid不同，则获取到的openid就不同），可用于永久标记一个用户
            //};
            ////if (total_fee > 200000)
            ////{
            ////    var user_name = RSAUtility.EncryptWithECB("", trueName);
            ////    transItem.Add("user_name", user_name);
            ////}

            //body["transfer_detail_list"] = new JArray { transItem }; //转账明细列表	transfer_detail_list	array	是	body发起批量转账的明细列表，最多三千笔

            //var message = $"POST\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            //var sign = RSAUtility.SignWithSHA256(privateKey, message);
            //var auth = $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{certSN}\",signature=\"{sign}\"";

            ////小程序下单，获取预支付交易会话标识
            ////直连商户：https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml
            //var result = Execute(uri, auth, body);
            //return result;
            return null;
        }


        #region Common Method
        private JObject Execute(string uri, string auth, JObject body)
        {
            var url = $"{baseUrl}{uri}";
            var method = body == null ? Method.GET : Method.POST;

            var client = new RestClient();
            var request = new RestRequest(url, method)
                .AddHeader("Content-Type", "application/json")
                .AddHeader("Accept", "application/json")
                .AddHeader("Authorization", $"WECHATPAY2-SHA256-RSA2048 {auth}");

            if (method == Method.POST)
            {
                //request.AddJsonBody(body);
                request.AddParameter("application/json", body.ToString(), ParameterType.RequestBody);
            }

            try
            {
                log.Info($"{method} {url} \n {body}");
                var response = client.Execute(request);
                if (!response.IsSuccessful)
                {
                    throw new Exception(response.Content);
                }

                if (response.StatusCode == System.Net.HttpStatusCode.OK && !string.IsNullOrEmpty(response.Content))
                {
                    log.Info(response.Content);
                    return JObject.Parse(response.Content);
                }
                else
                {
                    var msg = $"{(int)response.StatusCode}-{response.StatusDescription}";
                    log.Info(msg);
                    throw new Exception(msg);
                }
            }
            catch (Exception ex)
            {
                log.Error($"请求地址：{uri}，错误信息：{ex}");
                throw;
            }
        }

        /// <summary>
        /// 获取当前Unix时间戳
        /// </summary>
        /// <returns></returns>
        private long GetTimestamp()
        {
            return DateTimeOffset.Now.ToUnixTimeSeconds();
        }

        /// <summary>
        /// 获取随机字符串
        /// </summary>
        /// <returns></returns>
        private string GetNoncestr()
        {
            return Guid.NewGuid().ToString("N");
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="text">待加密的文本内容</param>
        /// <returns></returns>
        public string Encrypt(string text)
        {
            return text.ToHexString();
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="text">待解密的文本内容</param>
        /// <returns></returns>
        public string Decrypt(string text)
        {
            return text.FromHexString();
        }

        #endregion
    }
}
